from typing import Annotated

import re
from fastapi import Query
from pydantic import BaseModel, model_validator, ConfigDict
from app.utils import regexes, types, time
from app.models import responses


class AppFlag(BaseModel):
    app_flag: str

    @model_validator(mode='before')
    @classmethod
    def AppFlag_before(cls, data):
        data = types.safe_dict(data)
        data['app_flag'] = data.get('app_flag', '')
        return data

    @model_validator(mode='after')
    def AppFlag_after(self):
        if not self.app_flag:
            raise responses.FailureResponseError(10001, msg='App Flag 参数为必需项')

        return self


class Timestamp(BaseModel):
    timestamp: int

    @model_validator(mode='before')
    @classmethod
    def Timestamp_before(cls, data):
        data = types.safe_dict(data)
        data['timestamp'] = types.safe_int(data.get('timestamp', None), 0)
        return data

    @model_validator(mode='after')
    def Timestamp_after(self):
        if not self.timestamp:
            raise responses.FailureResponseError(10001, msg='时间戳为必需参数')

        if not re.fullmatch(regexes.TIMESTAMP, str(self.timestamp)):
            raise responses.FailureResponseError(10001, msg='时间戳格式错误')

        if self.timestamp > time.get_now_ts() + 5 or self.timestamp < time.get_now_ts() - 5:
            raise responses.FailureResponseError(10002)

        return self


class VerifyRequestSign(BaseModel):
    sign: str

    @model_validator(mode='before')
    @classmethod
    def VerifyRequestSign_before(cls, data):
        data = types.safe_dict(data)
        data['sign'] = data.get('sign', '')
        return data

    @model_validator(mode='after')
    def VerifyRequestSign_after(self):
        if len(self.sign) != 32:
            raise responses.FailureResponseError(10001, msg='请求签名格式不正确')

        return self


class DeviceAndCard(BaseModel):
    card: str
    device_code: str

    @model_validator(mode='before')
    @classmethod
    def DeviceAndCard_before(cls, data):
        data = types.safe_dict(data)
        data['card'] = data.get('card', '')
        data['device_code'] = data.get('device_code', '')
        return data

    @model_validator(mode='after')
    def DeviceAndCard_after(self):
        if len(self.card) == 0:
            raise responses.FailureResponseError(10001, msg='卡密为必需项')

        if len(self.card) > 64:
            raise responses.FailureResponseError(10001, msg='卡密长度不能超过 64 位')

        if len(self.device_code) == 0:
            raise responses.FailureResponseError(10001, msg='设备码为必需项')

        if not (32 <= len(self.device_code) <= 128):
            raise responses.FailureResponseError(10001, msg='设备码长度应介于 32-128 位')

        return self


class CardLoginJSON(VerifyRequestSign, DeviceAndCard, Timestamp, AppFlag):
    pass


class VerifyRequestSign(VerifyRequestSign, Timestamp, AppFlag):
    model_config = ConfigDict(extra='allow')


class CardToken(BaseModel):
    token: str

    @model_validator(mode='before')
    @classmethod
    def CardToken_before(cls, data):
        data = types.safe_dict(data)
        data['token'] = data.get('token', '')
        return data

    @model_validator(mode='after')
    def CardToken_after(self):
        if not self.token:
            raise responses.FailureResponseError(10001, msg='Token 参数为必需项')

        if not (32 <= len(self.token) <= 128):
            raise responses.FailureResponseError(10001, msg='Token 长度应介于 32-128 位')

        return self


class CardHeartbeat(VerifyRequestSign, DeviceAndCard, CardToken, Timestamp, AppFlag):
    pass


CardHeartbeatParams = Annotated[CardHeartbeat, Query()]


class CardLogoutJSON(VerifyRequestSign, DeviceAndCard, CardToken, Timestamp, AppFlag):
    pass


class CardUnbindJSON(VerifyRequestSign, DeviceAndCard, CardToken, Timestamp, AppFlag):
    pass


class CardInfo(VerifyRequestSign, Timestamp, AppFlag):
    card: str

    @model_validator(mode='before')
    @classmethod
    def CardInfo_before(cls, data):
        data = types.safe_dict(data)
        data['card'] = data.get('card', '')
        return data

    @model_validator(mode='after')
    def CardInfo_after(self):
        if len(self.card) == 0:
            raise responses.FailureResponseError(10001, msg='卡密为必需项')

        if len(self.card) > 64:
            raise responses.FailureResponseError(10001, msg='卡密长度不能超过 64 位')

        return self


CardInfoParams = Annotated[CardInfo, Query()]


class CardRechargeJSON(VerifyRequestSign, Timestamp, AppFlag):
    old_card: str
    new_card: str

    @model_validator(mode='before')
    @classmethod
    def CardRechargeJSON_before(cls, data):
        data = types.safe_dict(data)
        data['old_card'] = data.get('old_card', '')
        data['new_card'] = data.get('new_card', '')
        return data

    @model_validator(mode='after')
    def CardRechargeJSON_after(self):
        if len(self.old_card) == 0:
            raise responses.FailureResponseError(10001, msg='需要充值的卡密为必需项')

        if len(self.old_card) > 64:
            raise responses.FailureResponseError(10001, msg='卡密长度不能超过 64 位')

        if len(self.new_card) == 0:
            raise responses.FailureResponseError(10001, msg='被消耗的卡密为必需项')

        if len(self.new_card) > 64:
            raise responses.FailureResponseError(10001, msg='卡密长度不能超过 64 位')

        return self


class AppFlagAndTime(VerifyRequestSign, Timestamp, AppFlag):
    pass


AppFlagAndTimeParams = Annotated[AppFlagAndTime, Query()]


class AppCheckUpdate(VerifyRequestSign, Timestamp, AppFlag):
    version: str

    @model_validator(mode='before')
    @classmethod
    def AppCheckUpdate_before(cls, data):
        data = types.safe_dict(data)
        data['version'] = data.get('version', '')
        return data

    @model_validator(mode='after')
    def AppCheckUpdate_after(self):
        if len(self.version) == 0:
            raise responses.FailureResponseError(10001, msg='版本号为必需项')

        if len(self.version) > 20:
            raise responses.FailureResponseError(10001, msg='版本号的长度不能超过 20 位')

        return self


AppCheckUpdateParams = Annotated[AppCheckUpdate, Query()]


class TrialLoginJSON(VerifyRequestSign, Timestamp, AppFlag):
    device_code: str

    @model_validator(mode='before')
    @classmethod
    def TrialLoginJSON_before(cls, data):
        data = types.safe_dict(data)
        data['device_code'] = data.get('device_code', '')
        return data

    @model_validator(mode='after')
    def TrialLoginJSON_after(self):
        if len(self.device_code) == 0:
            raise responses.FailureResponseError(10001, msg='设备码为必需项')

        if not (32 <= len(self.device_code) <= 128):
            raise responses.FailureResponseError(10001, msg='设备码长度应介于 32-128 位')

        return self


TrialHeartbeatParams = Annotated[TrialLoginJSON, Query()]


class UpdateExtraDataJSON(CardInfo, CardToken):
    device_code: str
    extra_data: dict

    @model_validator(mode='before')
    @classmethod
    def UpdateExtraDataJSON_before(cls, data):
        data = types.safe_dict(data)
        data['device_code'] = data.get('device_code', '')
        data['extra_data'] = types.safe_loads_json(data.get('extra_data'))
        return data

    @model_validator(mode='after')
    def UpdateExtraDataJSON_after(self):
        if len(self.device_code) == 0:
            raise responses.FailureResponseError(10001, msg='设备码为必需项')

        if not (32 <= len(self.device_code) <= 128):
            raise responses.FailureResponseError(10001, msg='设备码长度应介于 32-128 位')

        if len(str(self.extra_data)) > 1024:
            raise responses.FailureResponseError(10001, msg='额外数据长度不能超过 1024 个字符')

        return self
